﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using CarShop.Domain.Entities;
using CarShop.Security.Contracts;
using CarShop.Security.Contracts.Exceptions;
using CarShop.UserInterface.Wpf.Core.Commands;
using CarShop.UserInterface.Wpf.Core.EventArgs;
using CarShop.UserInterface.Wpf.Core.Infrastructure;
using CarShop.UserInterface.Wpf.Core.ViewModels;

namespace CarShop.UserInterface.Wpf.ViewModels
{
    public class AuthenticationWindowViewModel : ViewModelBase
    {
        #region Events

        public event EventHandler<AuthenticationEventArgs> LoggedIn;

        #endregion


        #region Fields

        private readonly IAuthenticationService _authenticationService;
        private readonly IMembershipProvider _membershipProvider;
        private string _userName;
        private string _password;
        private string _error;
        private bool _logging;

        private ICommand _logInCommand;

        #endregion


        #region Properties

        public string UserName
        {
            get
            {
                return _userName;
            }
            set
            {
                _userName = value;
            }
        }

        public string Password
        {
            get
            {
                return _password;
            }
            set
            {
                _password = value;
            }
        }

        public string Error
        {
            get
            {
                return _error;
            }
            set
            {
                if (_error == value)
                {
                    return;
                }

                _error = value;
                this.OnPropertyChanged("Error");
            }
        }

        public bool Logging
        {
            get
            {
                return _logging;
            }
            set
            {
                if (_logging == value)
                {
                    return;
                }

                _logging = value;
                this.OnPropertyChanged("Logging");
            }
        }

        public ICommand LogInCommand
        {
            get
            {
                return _logInCommand ??
                       (_logInCommand = new SimpleCommand(this.OnLogIn, this.CanLogIn));
            }
        }

        #endregion


        public AuthenticationWindowViewModel(IAuthenticationService authenticationService, IMembershipProvider membershipProvider)
        {
            this.DisplayName = "Car Shop";

            _authenticationService = authenticationService;
            _membershipProvider = membershipProvider;
        }


        #region Command Handlers

        protected virtual void OnLogIn()
        {
            this.Error = null;
            this.Logging = true;

            var task = new Task<LoginCheckResults>(
                () =>
                    {
                        Thread.Sleep(1000);
                        LoginCheckResults result = new LoginCheckResults() { CheckTime = DateTime.UtcNow };

                        try
                        {
                            _membershipProvider.ValidateUser(this.UserName, this.Password);

                            User user = _membershipProvider.FindUserByLoginOrEmail(UserName);
                            CarShopIdentity identity = new CarShopIdentity(user);
                            _authenticationService.SignIn(identity);
                            result.Status = LoginCheckStatus.Success;
                        }
                        catch (UserValidationException e)
                        {
                            result.Status = LoginCheckStatus.Fail;
                            result.Exception = e;
                        }

                        return result;

                    });

            task.ContinueWith(
                t =>
                    {
                        this.Logging = false;

                        switch (t.Result.Status)
                        {
                            case LoginCheckStatus.Success:
                                this.OnLoggedIn(t.Result);
                                break;
                            case LoginCheckStatus.Fail:
                                this.Error = t.Result.Exception.Message;
                                break;
                        }
                    },
                CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, TaskScheduler.FromCurrentSynchronizationContext());
            task.ContinueWith(
                t =>
                    {
                        this.Logging = false;
                        this.Error = "Some error while logging";
                    },
                CancellationToken.None, TaskContinuationOptions.NotOnRanToCompletion, TaskScheduler.FromCurrentSynchronizationContext());

            task.Start();
        }

        protected virtual bool CanLogIn()
        {
            return !this.Logging && !string.IsNullOrWhiteSpace(this.UserName) && this.Password.Length > 0;
        }

        #endregion


        protected virtual void OnLoggedIn(LoginCheckResults loginCheckResults)
        {
            var handler = Interlocked.CompareExchange(ref LoggedIn, null, null);

            if (handler != null)
            {
                handler(this, new AuthenticationEventArgs(loginCheckResults));
            }
        }
    }
}
